/* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/


/*************************************************************************
 * File: exdata.cpp
 *************************************************************************
 *\author: starlove
 *************************************************************************/

#include <codec/exdata.h>
#include <codec/exdata_wrapper.h>
#include <platform/debug.h>
#include <stdio.h>

CMapData::CMapData(LPBUFFER_WRAPPER pBuffer)
{
    this->Load(pBuffer);
}

CMapData::~CMapData()
{
    m_datas.clear();
}

void CMapData::Load(LPBUFFER_WRAPPER pBuffer)
{
    if (!pBuffer)
        return;

    m_datas.clear();
    LPWRAPPER_KEYVALUE_DATA_HEADER p = NULL;
    unsigned int n = 0;
    unsigned int ncount = 0;
    BUFFER_WRAPPER bw;

    LPWRAPPER_DATA_HEADER pheader = (LPWRAPPER_DATA_HEADER)pBuffer->read(sizeof(WRAPPER_DATA_HEADER));
    if (pheader->tp != DTP_MAP)
    {
        pBuffer->forward(sizeof(WRAPPER_DATA_HEADER));
        return;
    }
    ncount = pheader->size;
    CODE_HASH_KEY skey;

    while((n < ncount) && (p = (LPWRAPPER_KEYVALUE_DATA_HEADER)pBuffer->read(sizeof(WRAPPER_KEYVALUE_DATA_HEADER))))
    {
        void *pKeyData = ((char *)p) + sizeof(WRAPPER_KEYVALUE_DATA_HEADER);

        switch (p->ktp)
        {
        case DTP_STR:
        {
            skey = (const char *)pKeyData;
            skey += "(s)";
        }
        break;
        case DTP_INT:
        {
            skey = ConvertToStr<int>(*(int *)pKeyData);
            skey += "(v)";
        }
        break;
        case DTP_FLOAT:
        {
            skey = ConvertToStr<float>(*(float *)pKeyData);
            skey += "(v)";
        }
        break;
        case DTP_INT64:
        {
            skey = ConvertToStr<INT64>(*(INT64 *)pKeyData);
            skey += "(v)";
        }
        break;
        default:
            continue;
        }

        m_datas[skey] = p;

        void *pData = (void *)(((char *)pKeyData) + p->ksize);
        char tp = p->tp;
        if (tp == DTP_BUFFER || tp == DTP_PBUFFER)
        {
            LPWRAPPER_DATA_HEADER pH = (LPWRAPPER_DATA_HEADER)pData;
            tp =  (pH->tp);
        }
        switch (tp)
        {
        case DTP_MAP:
        {
            CMapData cmap;
            bw.readonly_ref(pData, p->size);
            cmap.Load(&bw);
            m_mapdatas[p] = cmap;
        }
        break;
        case DTP_LIST:
        {
            CListData clist;
            bw.readonly_ref(pData, p->size);
            clist.Load(&bw);
            m_listdatas[p] = clist;
        }
        break;
        }

        if(!pBuffer->skip(p->ksize + p->size))
        {
            DEBUG_INFO_CODEC("data buffer is invalid!");
            break;
        }
        n++;
    }
}

unsigned int CMapData::GetSize()
{
    return m_datas.size();
}

CListData::CListData(LPBUFFER_WRAPPER pBuffer)
{
    this->Load(pBuffer);
}

CListData::~CListData()
{
    m_datas.clear();
}

void CListData::Load(LPBUFFER_WRAPPER pBuffer)
{
    if (!pBuffer)
        return;

    m_datas.clear();
    LPWRAPPER_DATA_HEADER p = NULL;
    unsigned int n = 0;
    unsigned int ncount = 0;
    BUFFER_WRAPPER bw;

    LPWRAPPER_DATA_HEADER pheader = (LPWRAPPER_DATA_HEADER)pBuffer->read(sizeof(WRAPPER_DATA_HEADER));
    if (pheader->tp != DTP_LIST)
    {
        pBuffer->forward(sizeof(WRAPPER_DATA_HEADER));
        return;
    }
    ncount = pheader->size;

    while((n < ncount) && (p = (LPWRAPPER_DATA_HEADER)pBuffer->read(sizeof(WRAPPER_DATA_HEADER))))
    {
        m_datas.push_back(p);

        void *pData = (void *)(((char *)p) + sizeof(WRAPPER_DATA_HEADER));
        char tp = p->tp;
        if (tp == DTP_BUFFER || tp == DTP_PBUFFER)
        {
            LPWRAPPER_DATA_HEADER pH = (LPWRAPPER_DATA_HEADER)pData;
            tp =  (pH->tp);
        }
        switch (tp)
        {
        case DTP_MAP:
        {
            CMapData cmap;
            bw.readonly_ref(pData, p->size);
            cmap.Load(&bw);
            m_mapdatas[p] = cmap;
        }
        break;
        case DTP_LIST:
        {
            CListData clist;
            bw.readonly_ref(pData, p->size);
            clist.Load(&bw);
            m_listdatas[p] = clist;
        }
        break;
        }

        if(!pBuffer->skip(p->size))
        {
            DEBUG_INFO_CODEC("data buffer is invalid!");
            break;
        }
        n++;
    }
}

unsigned int CListData::GetSize()
{
    return m_datas.size();
}

void *IContainerData::GetMapDataPtr(void * pv)
{
    LIST_MAPS::iterator it = m_mapdatas.find(pv);
    if( it != m_mapdatas.end() )
    {
        return &it->second;
    }
    else
        return NULL;
}

void *IContainerData::GetListDataPtr(void * pv)
{
    LIST_LISTS::iterator it = m_listdatas.find(pv);
    if( it != m_listdatas.end() )
    {
        return &it->second;
    }
    else
        return NULL;
}

